#!/usr/bin/env bash

#
# Linux init script for the Apache Tomcat servlet container.
#
# chkconfig: 2345 96 14
# description: The Apache Tomcat servlet container.
# processname: @PKG_NAME@
# config: @PKG_ROOT@/conf/@PKG_NAME@-env.sh
#
# Copyright (c) 2007-2011 Jason Brittain <jason.brittain@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ----------------------------------------------------------------------
# $Id$
#
# Author: Jason Brittain <jason.brittain@gmail.com>

# Source function library.
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
fi

APP_ENV="@PKG_ROOT@/conf/@PKG_NAME@-env.sh"

# Source the app config file, if it exists.
[ -r "$APP_ENV" ] && . "${APP_ENV}"

# The path to the Tomcat start/stop script.
TOMCAT_SCRIPT=$CATALINA_HOME/bin/catalina.sh

READLINK="`which readlink`"
BASENAME="`which basename`"
DIRNAME="`which dirname`"

# Detect the name of this script.
if [[ $READLINK =~ ^/ ]]; then
    LINK="`$READLINK -f $0`"
else
    PRG="$0"
    while [ -h "$PRG" ]; do
        ls=`ls -ld "$PRG"`
        link=`expr "$ls" : '.*-> \(.*\)$'`
        if expr "$link" : '/.*' > /dev/null; then
            PRG="$link"
        else
            PRG=`dirname "$PRG"`/"$link"
        fi
    done
    LINK=$PRG
fi

# Get the service name from the name of the init script.
SCRIPT_DIR="`$DIRNAME $0`"
if [[ $SCRIPT_DIR =~ /etc/rc\d*..d ]]; then
    # Resolve symlink paths like /etc/rc6.d/S96tomcat
    ls=`ls -ld "$0"`
    LINK=`expr "$ls" : '.*-> \(.*\)$'`
    if ! expr "$LINK" : '/.*' > /dev/null; then
        LINK=`dirname "$0"`/"$LINK"
    fi
    SERVICE_NAME="`$BASENAME $LINK`"
else
    SERVICE_NAME="`$BASENAME $0`"
fi

# If TOMCAT_USER is not set, use "tomcat".
if [ -z "$TOMCAT_USER" ]; then
    TOMCAT_USER="tomcat"
fi

# Since this init script will run $TOMCAT_SCRIPT, no environment
# settings should be defined here anymore.  Please use the
# @PKG_ROOT@/conf/@PKG_NAME@-env.sh file instead.

let RETVAL=0
JVM_PID="0"
JVM_RUNNING="false"

start() {
    echo -n "Starting $SERVICE_NAME: "

    checkJvmRunning
    if [ "$JVM_RUNNING" == "true" ]; then
        echo -n "\"$SERVICE_NAME\" JVM process already running. "
    else
        # Raise the process's maximum number of file descriptors to 8192.
        if [ "${UID}" == "0" ]; then
            # Raise the process's maximum number of file descriptors to 8192.
            ulimit -n 8192 || :
        fi

        # Exit with an explanation if our JAVA_HOME isn't found.
        if [ ! -d "$JAVA_HOME" ] && [ ! -d "$JRE_HOME" ]; then
            echo "JAVA_HOME of $JAVA_HOME not found."
            echo "See ${APP_ENV}"
            if [ -f /etc/rc.d/init.d/functions ]; then
                echo -n "Starting $SERVICE_NAME: "
                echo_failure
                echo
            fi
            return 1
        fi

        # Set JSSE_HOME -- it fixes some security issues.
        JSSE_HOME="$JAVA_HOME"
        if [ "$JSSE_HOME" == "" ]; then
            JSSE_HOME="$JRE_HOME"
        fi
        if [ -d "$JAVA_HOME/jre" ] && [ -r "$JAVA_HOME/jre" ]; then
            JSSE_HOME="$JAVA_HOME/jre"
        fi

        # Start Tomcat, running as the $TOMCAT_USER.
        if [ "$USER" == "$TOMCAT_USER" ]; then
            # We're already the $TOMCAT_USER so just exec the script.
            bash -c "set -a; . $APP_ENV; $TOMCAT_SCRIPT start" \
                >/dev/null 2>&1
        else
            if [ -x /etc/rc.d/init.d/functions -a -x /sbin/runuser ]; then
                runuser -s /bin/bash - $TOMCAT_USER \
                    -c "set -a; . $APP_ENV; $TOMCAT_SCRIPT start" &>/dev/null
            else
                su - $TOMCAT_USER -c "/bin/bash -c \
                    \"set -a; . $APP_ENV; $TOMCAT_SCRIPT start\"" \
                    >/dev/null 2>&1
            fi
        fi
        disown -a

        let RETVAL=$?

        # If the return value is zero, then the attempt to start it is
        # good so far.
        if [ $RETVAL -eq 0 ]; then
            # Sleep some seconds while Tomcat begins to start, then check it.
            sleep 7
            checkJvmRunning
            if [ "$JVM_RUNNING" == "false" ]; then
                let RETVAL=1
            fi
        fi
    fi

    # Output "[  OK  ]" or "[  FAILED  ]"
    if [ $RETVAL -eq 0 ]; then
        if [ -f /etc/rc.d/init.d/functions ]; then
            echo_success
            echo
        else
            echo "[  OK  ]"
        fi
    else
        if [ -f /etc/rc.d/init.d/functions ]; then
            echo_failure
            echo
        else
            echo "[  FAILED  ]"
        fi
    fi

    return $RETVAL
}

stop() {
    echo -n "Stopping $SERVICE_NAME: "

    checkJvmRunning
    if [ "$JVM_RUNNING" == "true" ]; then

        # Exit with an explanation if our JAVA_HOME isn't found.
        if [ ! -d "$JAVA_HOME" ] && [ ! -d "$JRE_HOME" ]; then
            echo "JAVA_HOME of $JAVA_HOME not found."
            echo "See ${APP_ENV}"
            echo -n "Stopping $SERVICE_NAME: "
            if [ -f /etc/rc.d/init.d/functions ]; then
                echo_failure
                echo
            else
                echo "[  FAILED  ]"
            fi
            return 1
        fi

        # Stop Tomcat, running as the $TOMCAT_USER.  We also unset any
        # JVM memory switches -- the stop client shouldn't start with those.
        if [ "$USER" == "$TOMCAT_USER" ]; then
            # We're already the $TOMCAT_USER so just exec the script.
            bash -c "set -a; . $APP_ENV; shopt -s extglob; \
                export JAVA_OPTS=\"\${JAVA_OPTS//-Xm[sx]+([0-9])[mM]}\"; \
                shopt -u extglob; $TOMCAT_SCRIPT stop" &>/dev/null
        else
            if [ -f /etc/rc.d/init.d/functions -a -x /sbin/runuser ]; then
                runuser -s /bin/bash - $TOMCAT_USER \
                    -c "set -a; . $APP_ENV; shopt -s extglob; \
                    export JAVA_OPTS=\"\${JAVA_OPTS//-Xm[sx]+([0-9])[mM]}\"; \
                    shopt -u extglob; $TOMCAT_SCRIPT stop" &>/dev/null
            else
                su - $TOMCAT_USER -c "/bin/bash -c \
                    \"set -a; . $APP_ENV; shopt -s extglob; \
                    export JAVA_OPTS=\"\${JAVA_OPTS//-Xm[sx]+([0-9])[mM]}\"; \
                    shopt -u extglob; $TOMCAT_SCRIPT stop\"" &>/dev/null
            fi
        fi

        let RETVAL=$?

        if [ $RETVAL -eq 0 ]; then

            checkJvmRunning
            if [ "$JVM_RUNNING" == "true" ]; then
                if [ ! $SHUTDOWN_WAIT ]; then
                    let SHUTDOWN_WAIT=5;
                fi

                # Loop here until either Tomcat shuts down on its own, or
                # until we've waited longer than SHUTDOWN_WAIT seconds.
                let count=0
                until [ "`ps -p $JVM_PID | grep -c $JVM_PID`" == "0" ] ||
                      [ $count -gt $SHUTDOWN_WAIT ]
                do
                    if [ $count -eq 0 ]; then
                        echo
                    fi
                    echo "Waiting for processes to exit.."
                    sleep 1
                    let count=$count+1
                done

                if [ $count -gt $SHUTDOWN_WAIT ]; then
                    # Tomcat is still running, so we'll send the JVM a
                    # SIGTERM signal and wait again.
                    echo "Sending the Tomcat processes a SIGTERM asking them" \
                         "to shut down gracefully.."
                    /bin/kill -15 $JVM_PID &>/dev/null

                    # Loop here until either Tomcat shuts down on its own, or
                    # until we've waited longer than SHUTDOWN_WAIT seconds.
                    let count=0
                    until [ "`ps -p $JVM_PID | grep -c $JVM_PID`" \
                          == "0" ] || [ $count -gt $SHUTDOWN_WAIT ]
                    do
                        echo "Waiting for processes to exit.."
                        sleep 1
                        let count=$count+1
                    done

                    if [ $count -gt $SHUTDOWN_WAIT ]; then
                        # Tomcat is still running, and just won't shut down.
                        # We'll kill the JVM process by sending it a SIGKILL
                        # signal and wait again for the JVM process to die.
                        echo "Killing processes which didn't stop after" \
                         "$SHUTDOWN_WAIT seconds."
                        /bin/kill -9 $JVM_PID &>/dev/null

                        # Loop here until either Tomcat shuts down on its own,
                        # or until we've waited longer than SHUTDOWN_WAIT
                        # seconds.
                        let count=0
                        until [ "`ps -p $JVM_PID | grep -c $JVM_PID`" \
                              == "0" ] || [ $count -gt $SHUTDOWN_WAIT ]
                        do
                            echo "Waiting for processes to exit.."
                            sleep 1
                            let count=$count+1
                        done

                        if [ $count -gt $SHUTDOWN_WAIT ]; then
                            # The JVM process won't shut down even with a
                            # SIGKILL, so there is something really wrong.
                            echo "The \"$SERVICE_NAME\" JVM process is wedged and" \
                                "won't shut down even when it is"
                            echo "sent a SIGKILL."
                            echo "Process ID $JVM_PID."

                            # Right here we may want to email an administrator.

                            let RETVAL=1
                        fi
                    fi

                    # We need to sleep here to make sure the JVM process dies.
                    sleep 2
                fi
            fi
        fi
    fi

    # Output "[  OK  ]" or "[  FAILED  ]"
    if [ $RETVAL -eq 0 ]; then
        if [ -f /etc/rc.d/init.d/functions ]; then
            echo_success
            echo
        else
            echo "[  OK  ]"
        fi
    else
        if [ -f /etc/rc.d/init.d/functions ]; then
            echo_failure
            echo
        else
            echo "[  FAILED  ]"
        fi
    fi

    return $RETVAL
}

getJvmPid() {
    JVM_PID="`ps awwx | grep \"jvm=$JVM_ID \" | grep -v grep | head -n 1 | \
        cut -c -6`"
    # Remove any spaces in the pid string.
    JVM_PID=${JVM_PID// /}
}

checkJvmRunning() {
    getJvmPid
    if [ "$JVM_PID" != "" ]; then
        JVM_RUNNING="true"
    else
        JVM_RUNNING="false"
    fi
}

interruptHandler() {
    return 0
}
trap interruptHandler HUP TERM QUIT INT ABRT ALRM TSTP KILL

# See how we were called.
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        if [ $RETVAL -eq 0 ]; then
            start
        fi
        ;;
    status)
        checkJvmRunning
        if [ "$JVM_RUNNING" == "true" ]; then
            echo "$SERVICE_NAME (pid $JVM_PID) is running."
            let RETVAL=0
        else
            echo "$SERVICE_NAME is not running."
            let RETVAL=1
        fi
        exit $RETVAL
        ;;
    condrestart)
        # If it's already running, restart it, otherwise don't start it.
        checkJvmRunning
        if [ "$JVM_RUNNING" == "true" ]; then
            stop
            if [ $RETVAL -eq 0 ]; then
                start
            fi
        fi
        ;;
    *)
        echo "Usage: $SERVICE_NAME {start|stop|restart|status|condrestart}"
        let RETVAL=1
        exit $RETVAL
esac

exit $RETVAL
